Last compiled on October, 2025
R Sienna example:
rm(list = ls())
fpackage.check <- function(packages) {
lapply(packages, FUN = function(x) {
if (!require(x, character.only = TRUE)) {
install.packages(x, dependencies = TRUE)
library(x, character.only = TRUE)
}
})
}
fsave <- function(x, file = NULL, location = "./data/processed/") {
ifelse(!dir.exists("data"), dir.create("data"), FALSE)
ifelse(!dir.exists("data/processed"), dir.create("data/processed"), FALSE)
if (is.null(file))
file = deparse(substitute(x))
datename <- substr(gsub("[:-]", "", Sys.time()), 1, 8)
totalname <- paste(location, datename, file, ".rda", sep = "")
save(x, file = totalname) #need to fix if file is reloaded as input name, not as x.
}
fload <- function(filename) {
load(filename)
get(ls()[ls() != "filename"])
}
fshowdf <- function(x, ...) {
knitr::kable(x, digits = 2, "html", ...) %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover")) %>%
kableExtra::scroll_box(width = "100%", height = "300px")
}
colorize <- function(x, color) {
sprintf("<span style='color: %s;'>%s</span>", color, x)
}
packages = c("RSiena", "devtools", "igraph")
fpackage.check(packages)
# devtools::install_github('JochemTolsma/RsienaTwoStep', build_vignettes=TRUE)
packages = c("RsienaTwoStep")
fpackage.check(packages)
NEED DATA - use build in datasets from RSIENNA ?s501 Is adjacency
matrix for network type 1. Goal: Follow steps in 7.1 for different
data:
Step 1. Define data
Dependent variable: ties
fpackage.check(packages)
[[1]]
NULL
Inspect networks. Remove NAs, make sure diagonal. Need to see binary
(not weighted)
Put networks in an array
dim(s501) #says 50x50: 50 rows, 50 columns in data.
nets <- array (data = c(s501, s502), dim = c(dim(s501), 2)) #
c(dim(s501),2)
# dimensions of array are number of columns and number of rows
could replace this with data set from last week
Define dependent - and independent - variable
c(dim(s501),2)
[1] 50 50 2
Now combine into dataset - if use Rsiena, need this.
alcohol <- s50a[,1]alcohol
Error: unexpected symbol in "alcohol <- s50a[,1]alcohol"
Now can look at myeff - look at starting values - has density of two
networks, reciprocity
Want much more statistics for model, though!!
Step 2:
Can see all effects that could include in the dataset. Which is a
lot. And this is a simple dataset. and yeah, its huge. Also can see that
the type depends on weight function (evaluation (), endowment (), and
creation ())
Example. Jochem wants to make tie with Jos. Jochem’s consideration to
make a tie with Jos could be different than consideration to maintain a
tie, could be different that decistions to break a tie. Can’t estimate
all three. Evalution: mechanisms the same for making as breaking,
endowment = maintaining, creation = if there are none then what is the
cost.
In this course: just use evaluation function. Assume mechanisms and
functions to make/break ties are similar. include degree for evaluation.
But what are all these effects? - should be able to calculate statistic
for each effect for an ego in a network… Mathematical formula in chapter
12.
myeff
effectName include fix test initialValue parm
1 basic rate parameter net TRUE FALSE FALSE 4.69604 0
2 outdegree (density) TRUE FALSE FALSE -1.48852 0
3 reciprocity TRUE FALSE FALSE 0.00000 0
Make sure to understand out degree and reciprocity effects -
statistics - will play around with this next week. Need to think of
theory for which statistics are relevant. - Look at literature for
statistics, think about it, play and see if effects exists - how work in
reality? propose idea, write notation, see if effect exists in manual,
etc. Lots of notation because everyone is looking for their own effects.
- need to include more effects if what to.
Step 3: Look at intial data
- good for deciding statistics to use.
print01Report(mydata)
# gives initial description of data
# reading network variables , covariates, density measures/changes in networks, tie changes between subsequent observations... calculate how much networks changed over time.
# dont use balance calculation
Step 4: Add effects
myeff <- includeEffects(myeff, isolateNet, inPop, outAct)
#outAct - outdegree related activity
outAct - look at the number of times I have and square that:
especially the people that have a lot of ties will send a lot of ties. -
evaluation function of tie1 0 ties, and tie1 4 ties - then at t2 people
who have ties are more likely to send more ties
We know tie distributions are skewed, some people send a lot of ties
and others dont.
inPop: in degree activity: people who receive a lot of in-degrees
send a lot of out-degrees
isolateNet: people without a lot of indegree nets.
Can see that starting values are 0 – hypothesis testing
Step 5: Estimation
myeff <- includeEffects(myeff, isolateNet, inPop, outAct)
effectNumber effectName shortName include fix test initialValue parm
1 78 indegree - popularity inPop TRUE FALSE FALSE 0 0
2 106 outdegree - activity outAct TRUE FALSE FALSE 0 0
3 149 network-isolate isolateNet TRUE FALSE FALSE 0 0
Now have first estimated Rsiena model!
- see:negative out degree
- 2.4 reciprocity: is important then in this model
- indegree populaty is popular but not significant…
if significant: more indegrees- more likely to send later. people
with more out-degrees - more likely to send less (negative). isolate
more likely to be alone.
Need to think of model that makes sense in this
REVIEWING RSIENA NOW - negative degree - density is less than .5 -
interpretations - Mailing list for TOM
- Now: re-read chapter 2 and chapter 5
Afternoon: play with estimating our own models Nice to do with our
own data - collaboration networks. Logic of RSIENA: took actor oriented
approach - works if ties are directed. if undirected network, logic is
different: the actor deciding on undirected tie is difficult. Advise:
for now treat as undirected - and then evaluate tie. undirected tie by
reach consensus, forced into concensus, etc - reciprocity matters less
now.
Now play with it
Now - referencing web scraping site
fcolnet <- function(data = scholars, university = "RU", discipline = "sociology", waves = list(c(2015,
2018), c(2019, 2023)), type = c("first")) {
# step 1
demographics <- do.call(rbind.data.frame, data$demographics)
demographics <- demographics %>%
mutate(Universiteit1.22 = replace(Universiteit1.22, is.na(Universiteit1.22), ""), Universiteit2.22 = replace(Universiteit2.22,
is.na(Universiteit2.22), ""), Universiteit1.24 = replace(Universiteit1.24, is.na(Universiteit1.24),
""), Universiteit2.24 = replace(Universiteit2.24, is.na(Universiteit2.24), ""), discipline.22 = replace(discipline.22,
is.na(discipline.22), ""), discipline.24 = replace(discipline.24, is.na(discipline.24), ""))
sample <- which((demographics$Universiteit1.22 %in% university | demographics$Universiteit2.22 %in%
university | demographics$Universiteit1.24 %in% university | demographics$Universiteit2.24 %in%
university) & (demographics$discipline.22 %in% discipline | demographics$discipline.24 %in% discipline))
demographics_soc <- demographics[sample, ]
scholars_sel <- lapply(scholars, "[", sample)
# step 2
ids <- demographics_soc$au_id
nwaves <- length(waves)
nets <- array(0, dim = c(nwaves, length(ids), length(ids)), dimnames = list(wave = 1:nwaves, ids,
ids))
dimnames(nets)
# step 3
df_works <- tibble(works_id = unlist(lapply(scholars_sel$work, function(l) l$id)), works_author = unlist(lapply(scholars_sel$work,
function(l) l$author), recursive = FALSE), works_year = unlist(lapply(scholars_sel$work, function(l) l$publication_year),
recursive = FALSE))
df_works <- df_works[!duplicated(df_works), ]
# step 4
if (type == "first") {
for (j in 1:nwaves) {
df_works_w <- df_works[df_works$works_year >= waves[[j]][1] & df_works$works_year <= waves[[j]][2],
]
for (i in 1:nrow(df_works_w)) {
ego <- df_works_w$works_author[i][[1]]$au_id[1]
alters <- df_works_w$works_author[i][[1]]$au_id[-1]
if (sum(ids %in% ego) > 0 & sum(ids %in% alters) > 0) {
nets[j, which(ids %in% ego), which(ids %in% alters)] <- 1
}
}
}
}
if (type == "last") {
for (j in 1:nwaves) {
df_works_w <- df_works[df_works$works_year >= waves[[j]][1] & df_works$works_year <= waves[[j]][2],
]
for (i in 1:nrow(df_works_w)) {
ego <- rev(df_works_w$works_author[i][[1]]$au_id)[1]
alters <- rev(df_works_w$works_author[i][[1]]$au_id)[-1]
if (sum(ids %in% ego) > 0 & sum(ids %in% alters) > 0) {
nets[j, which(ids %in% ego), which(ids %in% alters)] <- 1
}
}
}
}
if (type == "all") {
for (j in 1:nwaves) {
df_works_w <- df_works[df_works$works_year >= waves[[j]][1] & df_works$works_year <= waves[[j]][2],
]
for (i in 1:nrow(df_works_w)) {
egos <- df_works_w$works_author[i][[1]]$au_id
if (sum(ids %in% egos) > 0) {
nets[j, which(ids %in% egos), which(ids %in% egos)] <- 1
}
}
}
}
output <- list()
output$data <- scholars_sel
output$nets <- nets
return(output)
}
Example in class from 10 October Siena dependent variable
# Step 1: load data
library(RSiena)
?sienaDependent #look for examples - script for how to run stuff
# then check waves available
s501 #network at timepoint 1
s502 #network at timepoint 2
s503 #network at timepoint
mynet1 <- sienaDependent(array(c(s501, s502, s503), dim=c(50, 50, 3)))
mybeh <- sienaDependent(s50a, type="behavior")
# look for smoking and drinking behaviors
smoke <- s50s #time varying covariate. Time constant covar - varCovar
smoke <- varCovar(s50s)
mydata_example <- sienaDataCreate(mynet1, mybeh, smoke)
# Step 2: look at data
#print report on data reports
print01Report(mydata_example)
# Step 3: add effects
myeff_example <- getEffects(mydata_example)
myeff_example
myeff_example <- includeEffects(myeff_example, unequalX, name="mynet1", interaction1 = "smoke")
myeff_example
#make algorithm to then estimate it
algo_ex <- sienaAlgorithmCreate(projname = "test_ex")
answer_ex <- siena07(algo_ex, data=mydata_example, effects=myeff_example, returnDeps = TRUE)
answer_ex
#does it change if dependent X
myeff_example <- includeEffects(myeff_example, unequalX, name="mynet1", interaction1 = "mybeh") #name = network dependent variable, interaction 1 is covariate (smoking) - if have multiple netowrks, then could have unequalX with respect to X. We replaced smoke with my behavior, and rerun the siena model. This is an algorithm, can ask RSiena to reference previous result with 'prevans=ANS' after returnDepts = TRUE
answer_ex <- siena07(algo_ex, data=mydata_example, effects=myeff_example, returnDeps = TRUE)
answer_ex
# looking at results, mybeh = drinking -- ego less likely to spend time with people who drink more or less than them. ego also less likely to spend time with people who smoke more or less, to a lesser extent. Can use unequalX for dependent variables and covariates. key difference in estimation procedure:
# we are also modeling behavioral results - behavior changing over time, simulated via ministep logic (one step up or down). The crucial difference: during the algorithm
#If count statistic for smoke, then between time point 1 and 2 we use value from timepoint 1. between 2-3, use time point 2. But within the variable, the ego level behavior is changing. is not using the value as observed at t1 - it is using the value as is currently simulated.
#could exclude variable to then include as covariate effect.
mybeh <- sienaDependent(s50a, type="behavior") #defined as dependent variable
drinking <- varCovar(s50a) #defined as covariate variable
#update data object:
mydata_example <- sienaDataCreate(mynet1, mybeh, drinking, smoke)
#and effects object:
myeff_example <- includeEffects(myeff_example, unequalX, name="mynet1", interaction1 = "smoke")
myeff_example <- includeEffects(myeff_example, unequalX, name="mynet1", interaction1 = "drinking")
algo_ex2 <- sienaAlgorithmCreate(projname = "test_ex")
answer_ex <- siena07(algo_ex2, data=mydata_example, effects=myeff_example, returnDeps = TRUE)
answer_ex
#then the network dynamics change
# interpretation of the rate constant - the average amount of ministeps each ego is making between the two observations
#behavioral dynamics:
# the rate constant: the number of steps in the behavioral aspect
#statistic for linear shape - linear shape effect - the value of the *centered* behavioral variable (average in the total sample).
# if positive, try to increase behavior. effect is z1 (zed score), with the options of 1, 0, or -1. behavior increases because positively evaluates 1 more than 0, more than -1. At some point, though, behavior will stop increasing - that is z2 (squared!). so, parameter moderates itself with time??
# these are the minimum effects to include, because it predicts mean value observe in dataset. 2 parameters - estimate mean behavior. based on model results, what is the mean value.
# behavioral variables in dataset - everything observed that changes. ex., position (functie), citations, interdisciplinarity score. Problem: is time window large enought to see change? and over time, behavioral variable is only changing - which then must be calculated as continuous depended variable.
LS0tDQp0aXRsZTogInJzaWVuYSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyLCBnbG9iYWxzZXR0aW5ncywgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpsaWJyYXJ5KGtuaXRyKQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpvcHRzX2NodW5rJHNldCh0aWR5Lm9wdHM9bGlzdCh3aWR0aC5jdXRvZmY9MTAwKSx0aWR5PVRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLGNvbW1lbnQgPSAiIz4iLCBjYWNoZT1UUlVFLCBjbGFzcy5zb3VyY2U9YygidGVzdCIpLCBjbGFzcy5vdXRwdXQ9YygidGVzdDIiKSkNCm9wdGlvbnMod2lkdGggPSAxMDApDQpyZ2w6OnNldHVwS25pdHIoKQ0KDQoNCmNvbG9yaXplIDwtIGZ1bmN0aW9uKHgsIGNvbG9yKSB7c3ByaW50ZigiPHNwYW4gc3R5bGU9J2NvbG9yOiAlczsnPiVzPC9zcGFuPiIsIGNvbG9yLCB4KSB9DQoNCg0KYGBgDQoNCmBgYHtyIGtsaXBweSwgZWNobz1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0Ka2xpcHB5OjprbGlwcHkocG9zaXRpb24gPSBjKCd0b3AnLCAncmlnaHQnKSkNCiNrbGlwcHk6OmtsaXBweShjb2xvciA9ICdkYXJrcmVkJykNCiNrbGlwcHk6OmtsaXBweSh0b29sdGlwX21lc3NhZ2UgPSAnQ2xpY2sgdG8gY29weScsIHRvb2x0aXBfc3VjY2VzcyA9ICdEb25lJykNCmBgYA0KDQpMYXN0IGNvbXBpbGVkIG9uIGByIGZvcm1hdChTeXMudGltZSgpLCAnJUIsICVZJylgDQoNCjxicj4NCg0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCg0KDQoNCg0KIyBSIFNpZW5uYSBleGFtcGxlOiANCg0KDQpgYGB7cn0NCnJtKGxpc3QgPSBscygpKQ0KDQpmcGFja2FnZS5jaGVjayA8LSBmdW5jdGlvbihwYWNrYWdlcykgew0KICAgIGxhcHBseShwYWNrYWdlcywgRlVOID0gZnVuY3Rpb24oeCkgew0KICAgICAgICBpZiAoIXJlcXVpcmUoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkgew0KICAgICAgICAgICAgaW5zdGFsbC5wYWNrYWdlcyh4LCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgICAgICAgICAgbGlicmFyeSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQogICAgICAgIH0NCiAgICB9KQ0KfQ0KDQpmc2F2ZSA8LSBmdW5jdGlvbih4LCBmaWxlID0gTlVMTCwgbG9jYXRpb24gPSAiLi9kYXRhL3Byb2Nlc3NlZC8iKSB7DQogICAgaWZlbHNlKCFkaXIuZXhpc3RzKCJkYXRhIiksIGRpci5jcmVhdGUoImRhdGEiKSwgRkFMU0UpDQogICAgaWZlbHNlKCFkaXIuZXhpc3RzKCJkYXRhL3Byb2Nlc3NlZCIpLCBkaXIuY3JlYXRlKCJkYXRhL3Byb2Nlc3NlZCIpLCBGQUxTRSkNCiAgICBpZiAoaXMubnVsbChmaWxlKSkNCiAgICAgICAgZmlsZSA9IGRlcGFyc2Uoc3Vic3RpdHV0ZSh4KSkNCiAgICBkYXRlbmFtZSA8LSBzdWJzdHIoZ3N1YigiWzotXSIsICIiLCBTeXMudGltZSgpKSwgMSwgOCkNCiAgICB0b3RhbG5hbWUgPC0gcGFzdGUobG9jYXRpb24sIGRhdGVuYW1lLCBmaWxlLCAiLnJkYSIsIHNlcCA9ICIiKQ0KICAgIHNhdmUoeCwgZmlsZSA9IHRvdGFsbmFtZSkgICNuZWVkIHRvIGZpeCBpZiBmaWxlIGlzIHJlbG9hZGVkIGFzIGlucHV0IG5hbWUsIG5vdCBhcyB4LiANCn0NCg0KZmxvYWQgPC0gZnVuY3Rpb24oZmlsZW5hbWUpIHsNCiAgICBsb2FkKGZpbGVuYW1lKQ0KICAgIGdldChscygpW2xzKCkgIT0gImZpbGVuYW1lIl0pDQp9DQoNCmZzaG93ZGYgPC0gZnVuY3Rpb24oeCwgLi4uKSB7DQogICAga25pdHI6OmthYmxlKHgsIGRpZ2l0cyA9IDIsICJodG1sIiwgLi4uKSAlPiUNCiAgICAgICAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkgJT4lDQogICAgICAgIGthYmxlRXh0cmE6OnNjcm9sbF9ib3god2lkdGggPSAiMTAwJSIsIGhlaWdodCA9ICIzMDBweCIpDQp9DQoNCmNvbG9yaXplIDwtIGZ1bmN0aW9uKHgsIGNvbG9yKSB7DQogICAgc3ByaW50ZigiPHNwYW4gc3R5bGU9J2NvbG9yOiAlczsnPiVzPC9zcGFuPiIsIGNvbG9yLCB4KQ0KfQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnBhY2thZ2VzID0gYygiUlNpZW5hIiwgImRldnRvb2xzIiwgImlncmFwaCIpDQpmcGFja2FnZS5jaGVjayhwYWNrYWdlcykNCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCdKb2NoZW1Ub2xzbWEvUnNpZW5hVHdvU3RlcCcsIGJ1aWxkX3ZpZ25ldHRlcz1UUlVFKQ0KcGFja2FnZXMgPSBjKCJSc2llbmFUd29TdGVwIikNCmZwYWNrYWdlLmNoZWNrKHBhY2thZ2VzKQ0KYGBgDQoNCk5FRUQgREFUQSAtIHVzZSBidWlsZCBpbiBkYXRhc2V0cyBmcm9tIFJTSUVOTkEgDQo/czUwMQ0KSXMgYWRqYWNlbmN5IG1hdHJpeCBmb3IgbmV0d29yayB0eXBlIDEuIEdvYWw6IEZvbGxvdyBzdGVwcyBpbiA3LjEgZm9yIGRpZmZlcmVudCBkYXRhOg0KDQojIFN0ZXAgMS4gRGVmaW5lIGRhdGENCkRlcGVuZGVudCB2YXJpYWJsZTogdGllcyANCg0KDQpgYGB7cn0NCnM1MDEgI25ldHdvcmsgYXQgdGltZXBvaW50IDENCnM1MDIgI25ldHdvcmsgYXQgdGltZXBvaW50IDINCmBgYA0KDQoNCkluc3BlY3QgbmV0d29ya3MuIFJlbW92ZSBOQXMsIG1ha2Ugc3VyZSBkaWFnb25hbC4gTmVlZCB0byBzZWUgYmluYXJ5IChub3Qgd2VpZ2h0ZWQpDQpgYGB7cn0NCg0KYGBgDQoNCg0KUHV0IG5ldHdvcmtzIGluIGFuIGFycmF5DQpgYGB7cn0NCg0KZGltKHM1MDEpICNzYXlzIDUweDUwOiA1MCByb3dzLCA1MCBjb2x1bW5zIGluIGRhdGEuIA0KDQpuZXRzIDwtIGFycmF5IChkYXRhID0gYyhzNTAxLCBzNTAyKSwgZGltID0gYyhkaW0oczUwMSksIDIpKSAjDQpjKGRpbShzNTAxKSwyKQ0KDQojIGRpbWVuc2lvbnMgb2YgYXJyYXkgYXJlIG51bWJlciBvZiBjb2x1bW5zIGFuZCBudW1iZXIgb2Ygcm93cyANCmBgYA0KIGNvdWxkIHJlcGxhY2UgdGhpcyB3aXRoIGRhdGEgc2V0IGZyb20gbGFzdCB3ZWVrIA0KIA0KIA0KRGVmaW5lIGRlcGVuZGVudCAtIGFuZCBpbmRlcGVuZGVudCAtIHZhcmlhYmxlDQpgYGB7cn0NCg0KbmV0IDwtIHNpZW5hRGVwZW5kZW50KG5ldHMpICNkZXBlbmRlbnQgdmFyaWFibGUgDQoNCiAgIyBpbmRlcGVuZGVudCB2YXJpYWJsZSAtIHM1MGEgLSB3ZSB3aWxsIHRha2UgZmlyc3Qgd2F5IA0KYWxjb2hvbCA8LSBzNTBhWywxXWFsY29ob2wNCiAjIGRvbid0IG5lZWQgd2F2ZSAyIC0ganVzdCBtb2RlbGluZyBhdCBpbmRlcGVuZGVudCB2YXJpYWJsZSwgaW5mbHVlbmNpbmcgYWxsIG1pbmlzdGVwcyBiZXR3ZWVuIHRpbWUgMSBhbmQgdGltZSAyIA0KYWxjb2hvbCANCiANCmFsY29ob2wgPC0gY29Db3ZhcihhbGNvaG9sKSMgYXQgYWN0b3IgbGV2ZWwgLSBtZWFuIGNlbnRlcmVkIC0gaXMgYSB0aW1lIGNvbnN0YW50IGNvVmFyaWF0ZSANCmBgYA0KDQpOb3cgY29tYmluZSBpbnRvIGRhdGFzZXQgLSBpZiB1c2UgUnNpZW5hLCBuZWVkIHRoaXMuIA0KYGBge3J9DQpteWRhdGEgPC0gc2llbmFEYXRhQ3JlYXRlKG5ldCwgYWxjb2hvbCkNCg0KbXllZmYgPC0gZ2V0RWZmZWN0cyhteWRhdGEpICNoYXZlIGEgbG9vayANCm15ZWZmDQpgYGANCk5vdyBjYW4gbG9vayBhdCBteWVmZiAtIGxvb2sgYXQgc3RhcnRpbmcgdmFsdWVzIC0gaGFzIGRlbnNpdHkgb2YgdHdvIG5ldHdvcmtzLCByZWNpcHJvY2l0eSANCg0KDQpXYW50IG11Y2ggbW9yZSBzdGF0aXN0aWNzIGZvciBtb2RlbCwgdGhvdWdoISEgDQoNCiMgU3RlcCAyOiANCkNhbiBzZWUgYWxsIGVmZmVjdHMgdGhhdCBjb3VsZCBpbmNsdWRlIGluIHRoZSBkYXRhc2V0LiBXaGljaCBpcyBhIGxvdC4gQW5kIHRoaXMgaXMgYSBzaW1wbGUgZGF0YXNldC4gYW5kIHllYWgsIGl0cyBodWdlLiBBbHNvIGNhbiBzZWUgdGhhdCB0aGUgdHlwZSBkZXBlbmRzIG9uIHdlaWdodCBmdW5jdGlvbiAoZXZhbHVhdGlvbiAoKSwgZW5kb3dtZW50ICgpLCBhbmQgY3JlYXRpb24gKCkpDQoNCkV4YW1wbGUuIEpvY2hlbSB3YW50cyB0byBtYWtlIHRpZSB3aXRoIEpvcy4gSm9jaGVtJ3MgY29uc2lkZXJhdGlvbiB0byBtYWtlIGEgdGllIHdpdGggSm9zIGNvdWxkIGJlIGRpZmZlcmVudCB0aGFuIGNvbnNpZGVyYXRpb24gdG8gbWFpbnRhaW4gYSB0aWUsIGNvdWxkIGJlIGRpZmZlcmVudCB0aGF0IGRlY2lzdGlvbnMgdG8gYnJlYWsgYSB0aWUuIENhbid0IGVzdGltYXRlIGFsbCB0aHJlZS4gRXZhbHV0aW9uOiBtZWNoYW5pc21zIHRoZSBzYW1lIGZvciBtYWtpbmcgYXMgYnJlYWtpbmcsIGVuZG93bWVudCA9IG1haW50YWluaW5nLCBjcmVhdGlvbiA9IGlmIHRoZXJlIGFyZSBub25lIHRoZW4gd2hhdCBpcyB0aGUgY29zdC4gDQoNCkluIHRoaXMgY291cnNlOiBqdXN0IHVzZSBldmFsdWF0aW9uIGZ1bmN0aW9uLiBBc3N1bWUgbWVjaGFuaXNtcyBhbmQgZnVuY3Rpb25zIHRvIG1ha2UvYnJlYWsgdGllcyBhcmUgc2ltaWxhci4gaW5jbHVkZSBkZWdyZWUgZm9yIGV2YWx1YXRpb24uIEJ1dCB3aGF0IGFyZSBhbGwgdGhlc2UgZWZmZWN0cz8gDQotICAgIHNob3VsZCBiZSBhYmxlIHRvIGNhbGN1bGF0ZSBzdGF0aXN0aWMgZm9yIGVhY2ggZWZmZWN0IGZvciBhbiBlZ28gaW4gYSBuZXR3b3JrLi4uIE1hdGhlbWF0aWNhbCBmb3JtdWxhIGluIGNoYXB0ZXIgMTIuIA0KDQoNCmBgYHtyfQ0KZWZmZWN0c0RvY3VtZW50YXRpb24obXllZmYpDQpgYGANCg0KDQpNYWtlIHN1cmUgdG8gdW5kZXJzdGFuZCBvdXQgZGVncmVlIGFuZCByZWNpcHJvY2l0eSBlZmZlY3RzIC0gc3RhdGlzdGljcyAtIHdpbGwgcGxheSBhcm91bmQgd2l0aCB0aGlzIG5leHQgd2Vlay4gTmVlZCB0byB0aGluayBvZiB0aGVvcnkgZm9yIHdoaWNoIHN0YXRpc3RpY3MgYXJlIHJlbGV2YW50LiANCi0gICAgTG9vayBhdCBsaXRlcmF0dXJlIGZvciBzdGF0aXN0aWNzLCB0aGluayBhYm91dCBpdCwgcGxheSBhbmQgc2VlIGlmIGVmZmVjdHMgZXhpc3RzIA0KLSAgICBob3cgd29yayBpbiByZWFsaXR5PyBwcm9wb3NlIGlkZWEsIHdyaXRlIG5vdGF0aW9uLCBzZWUgaWYgZWZmZWN0IGV4aXN0cyBpbiBtYW51YWwsIGV0Yy4gTG90cyBvZiBub3RhdGlvbiBiZWNhdXNlIGV2ZXJ5b25lIGlzIGxvb2tpbmcgZm9yIHRoZWlyIG93biBlZmZlY3RzLiANCi0gICAgbmVlZCB0byBpbmNsdWRlIG1vcmUgZWZmZWN0cyBpZiB3aGF0IHRvLiANCg0KYGBge3J9DQoNCmBgYA0KDQoNCg0KIyBTdGVwIDM6IExvb2sgYXQgaW50aWFsIGRhdGENCi0gICAgZ29vZCBmb3IgZGVjaWRpbmcgc3RhdGlzdGljcyB0byB1c2UuIA0KYGBge3J9DQpwcmludDAxUmVwb3J0KG15ZGF0YSkNCg0KIyBnaXZlcyBpbml0aWFsIGRlc2NyaXB0aW9uIG9mIGRhdGEgDQojIHJlYWRpbmcgbmV0d29yayB2YXJpYWJsZXMgLCBjb3ZhcmlhdGVzLCBkZW5zaXR5IG1lYXN1cmVzL2NoYW5nZXMgaW4gbmV0d29ya3MsIHRpZSBjaGFuZ2VzIGJldHdlZW4gc3Vic2VxdWVudCBvYnNlcnZhdGlvbnMuLi4gY2FsY3VsYXRlIGhvdyBtdWNoIG5ldHdvcmtzIGNoYW5nZWQgb3ZlciB0aW1lLiANCiMgZG9udCB1c2UgYmFsYW5jZSBjYWxjdWxhdGlvbiANCmBgYA0KDQojIFN0ZXAgNDogQWRkIGVmZmVjdHMNCg0KYGBge3J9DQpteWVmZiA8LSBpbmNsdWRlRWZmZWN0cyhteWVmZiwgaXNvbGF0ZU5ldCwgaW5Qb3AsIG91dEFjdCkNCg0KI291dEFjdCAtIG91dGRlZ3JlZSByZWxhdGVkIGFjdGl2aXR5IA0KYGBgDQoNCm91dEFjdA0KLSBsb29rIGF0IHRoZSBudW1iZXIgb2YgdGltZXMgSSBoYXZlIGFuZCBzcXVhcmUgdGhhdDogZXNwZWNpYWxseSB0aGUgcGVvcGxlIHRoYXQgaGF2ZSBhIGxvdCBvZiB0aWVzIHdpbGwgc2VuZCBhIGxvdCBvZiB0aWVzLiANCi0gZXZhbHVhdGlvbiBmdW5jdGlvbiBvZiB0aWUxIDAgdGllcywgYW5kIHRpZTEgNCB0aWVzIC0gdGhlbiBhdCB0MiBwZW9wbGUgd2hvIGhhdmUgdGllcyBhcmUgbW9yZSBsaWtlbHkgdG8gc2VuZCBtb3JlIHRpZXMgDQoNCldlIGtub3cgdGllIGRpc3RyaWJ1dGlvbnMgYXJlIHNrZXdlZCwgc29tZSBwZW9wbGUgc2VuZCBhIGxvdCBvZiB0aWVzIGFuZCBvdGhlcnMgZG9udC4gDQoNCmluUG9wOiBpbiBkZWdyZWUgYWN0aXZpdHk6IHBlb3BsZSB3aG8gcmVjZWl2ZSBhIGxvdCBvZiBpbi1kZWdyZWVzIHNlbmQgYSBsb3Qgb2Ygb3V0LWRlZ3JlZXMgDQoNCmlzb2xhdGVOZXQ6IHBlb3BsZSB3aXRob3V0IGEgbG90IG9mIGluZGVncmVlIG5ldHMuIA0KDQoNCg0KQ2FuIHNlZSB0aGF0IHN0YXJ0aW5nIHZhbHVlcyBhcmUgMCAtLSBoeXBvdGhlc2lzIHRlc3RpbmcgDQoNCiMgU3RlcCA1OiBFc3RpbWF0aW9uDQoNCmBgYHtyfQ0KbXlBbGdvcml0aG0gPC0gc2llbmFBbGdvcml0aG1DcmVhdGUocHJvam5hbWUgPSAidGVzdCIpDQoNCiMgZGVmaW5lIGFsZ29yaXRobSB0aGF0IHNheXMgaG93IEkgd2FudCB0byBlc3RpbWF0ZSBteSBtb2RlbC4gd2lsbCB1c2UgZGVmYXVsdHMuIA0KDQphbnNNMSA8LSBzaWVuYTA3KG15QWxnb3JpdGhtLCBkYXRhID0gbXlkYXRhLCBlZmZlY3RzID0gbXllZmYsIHJldHVybkRlcHMgPSBUUlVFKQ0KIyB0aGVuIHJ1biBpdCB0byBzZWUgDQoNCmFuc00xDQoNCmBgYA0KTm93IGhhdmUgZmlyc3QgZXN0aW1hdGVkIFJzaWVuYSBtb2RlbCEgDQoNCg0KLSBzZWU6bmVnYXRpdmUgb3V0IGRlZ3JlZSANCi0gMi40IHJlY2lwcm9jaXR5OiBpcyBpbXBvcnRhbnQgdGhlbiBpbiB0aGlzIG1vZGVsIA0KLSBpbmRlZ3JlZSBwb3B1bGF0eSBpcyBwb3B1bGFyIGJ1dCBub3Qgc2lnbmlmaWNhbnQuLi4gDQoNCmlmIHNpZ25pZmljYW50OiBtb3JlIGluZGVncmVlcy0gbW9yZSBsaWtlbHkgdG8gc2VuZCBsYXRlci4gcGVvcGxlIHdpdGggbW9yZSBvdXQtZGVncmVlcyAtIG1vcmUgbGlrZWx5IHRvIHNlbmQgbGVzcyAobmVnYXRpdmUpLiBpc29sYXRlIG1vcmUgbGlrZWx5IHRvIGJlIGFsb25lLiANCg0KDQpOZWVkIHRvIHRoaW5rIG9mIG1vZGVsIHRoYXQgbWFrZXMgc2Vuc2UgaW4gdGhpcw0KDQoNCmBgYHtyfQ0KDQpgYGANCg0KUkVWSUVXSU5HIFJTSUVOQSBOT1cNCi0gICBuZWdhdGl2ZSBkZWdyZWUgLSBkZW5zaXR5IGlzIGxlc3MgdGhhbiAuNSANCi0gICBpbnRlcnByZXRhdGlvbnMgDQotICAgTWFpbGluZyBsaXN0IGZvciBUT00NCg0KLSAgIE5vdzogcmUtcmVhZCBjaGFwdGVyIDIgYW5kIGNoYXB0ZXIgNSANCg0KQWZ0ZXJub29uOiBwbGF5IHdpdGggZXN0aW1hdGluZyBvdXIgb3duIG1vZGVscyANCk5pY2UgdG8gZG8gd2l0aCBvdXIgb3duIGRhdGEgLSBjb2xsYWJvcmF0aW9uIG5ldHdvcmtzLiANCkxvZ2ljIG9mIFJTSUVOQTogdG9vayBhY3RvciBvcmllbnRlZCBhcHByb2FjaCAtIHdvcmtzIGlmIHRpZXMgYXJlIGRpcmVjdGVkLiBpZiB1bmRpcmVjdGVkIG5ldHdvcmssIGxvZ2ljIGlzIGRpZmZlcmVudDogdGhlIGFjdG9yIGRlY2lkaW5nIG9uIHVuZGlyZWN0ZWQgdGllIGlzIGRpZmZpY3VsdC4gQWR2aXNlOiBmb3Igbm93IHRyZWF0IGFzIHVuZGlyZWN0ZWQgLSBhbmQgdGhlbiBldmFsdWF0ZSB0aWUuIA0KdW5kaXJlY3RlZCB0aWUgYnkgcmVhY2ggY29uc2Vuc3VzLCBmb3JjZWQgaW50byBjb25jZW5zdXMsIGV0YyAtIHJlY2lwcm9jaXR5IG1hdHRlcnMgbGVzcyBub3cuIA0KDQpgYGB7cn0NCg0KYGBgDQoNCiMgTm93IHBsYXkgd2l0aCBpdCANCg0KYGBge3J9DQoNCg0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQpOb3cgLSByZWZlcmVuY2luZyB3ZWIgc2NyYXBpbmcgc2l0ZSANCg0KYGBge3J9DQpmY29sbmV0IDwtIGZ1bmN0aW9uKGRhdGEgPSBzY2hvbGFycywgdW5pdmVyc2l0eSA9ICJSVSIsIGRpc2NpcGxpbmUgPSAic29jaW9sb2d5Iiwgd2F2ZXMgPSBsaXN0KGMoMjAxNSwNCiAgICAyMDE4KSwgYygyMDE5LCAyMDIzKSksIHR5cGUgPSBjKCJmaXJzdCIpKSB7DQoNCiAgICAjIHN0ZXAgMQ0KICAgIGRlbW9ncmFwaGljcyA8LSBkby5jYWxsKHJiaW5kLmRhdGEuZnJhbWUsIGRhdGEkZGVtb2dyYXBoaWNzKQ0KICAgIGRlbW9ncmFwaGljcyA8LSBkZW1vZ3JhcGhpY3MgJT4lDQogICAgICAgIG11dGF0ZShVbml2ZXJzaXRlaXQxLjIyID0gcmVwbGFjZShVbml2ZXJzaXRlaXQxLjIyLCBpcy5uYShVbml2ZXJzaXRlaXQxLjIyKSwgIiIpLCBVbml2ZXJzaXRlaXQyLjIyID0gcmVwbGFjZShVbml2ZXJzaXRlaXQyLjIyLA0KICAgICAgICAgICAgaXMubmEoVW5pdmVyc2l0ZWl0Mi4yMiksICIiKSwgVW5pdmVyc2l0ZWl0MS4yNCA9IHJlcGxhY2UoVW5pdmVyc2l0ZWl0MS4yNCwgaXMubmEoVW5pdmVyc2l0ZWl0MS4yNCksDQogICAgICAgICAgICAiIiksIFVuaXZlcnNpdGVpdDIuMjQgPSByZXBsYWNlKFVuaXZlcnNpdGVpdDIuMjQsIGlzLm5hKFVuaXZlcnNpdGVpdDIuMjQpLCAiIiksIGRpc2NpcGxpbmUuMjIgPSByZXBsYWNlKGRpc2NpcGxpbmUuMjIsDQogICAgICAgICAgICBpcy5uYShkaXNjaXBsaW5lLjIyKSwgIiIpLCBkaXNjaXBsaW5lLjI0ID0gcmVwbGFjZShkaXNjaXBsaW5lLjI0LCBpcy5uYShkaXNjaXBsaW5lLjI0KSwgIiIpKQ0KDQogICAgc2FtcGxlIDwtIHdoaWNoKChkZW1vZ3JhcGhpY3MkVW5pdmVyc2l0ZWl0MS4yMiAlaW4lIHVuaXZlcnNpdHkgfCBkZW1vZ3JhcGhpY3MkVW5pdmVyc2l0ZWl0Mi4yMiAlaW4lDQogICAgICAgIHVuaXZlcnNpdHkgfCBkZW1vZ3JhcGhpY3MkVW5pdmVyc2l0ZWl0MS4yNCAlaW4lIHVuaXZlcnNpdHkgfCBkZW1vZ3JhcGhpY3MkVW5pdmVyc2l0ZWl0Mi4yNCAlaW4lDQogICAgICAgIHVuaXZlcnNpdHkpICYgKGRlbW9ncmFwaGljcyRkaXNjaXBsaW5lLjIyICVpbiUgZGlzY2lwbGluZSB8IGRlbW9ncmFwaGljcyRkaXNjaXBsaW5lLjI0ICVpbiUgZGlzY2lwbGluZSkpDQoNCiAgICBkZW1vZ3JhcGhpY3Nfc29jIDwtIGRlbW9ncmFwaGljc1tzYW1wbGUsIF0NCiAgICBzY2hvbGFyc19zZWwgPC0gbGFwcGx5KHNjaG9sYXJzLCAiWyIsIHNhbXBsZSkNCg0KICAgICMgc3RlcCAyDQogICAgaWRzIDwtIGRlbW9ncmFwaGljc19zb2MkYXVfaWQNCiAgICBud2F2ZXMgPC0gbGVuZ3RoKHdhdmVzKQ0KICAgIG5ldHMgPC0gYXJyYXkoMCwgZGltID0gYyhud2F2ZXMsIGxlbmd0aChpZHMpLCBsZW5ndGgoaWRzKSksIGRpbW5hbWVzID0gbGlzdCh3YXZlID0gMTpud2F2ZXMsIGlkcywNCiAgICAgICAgaWRzKSkNCiAgICBkaW1uYW1lcyhuZXRzKQ0KDQogICAgIyBzdGVwIDMNCiAgICBkZl93b3JrcyA8LSB0aWJibGUod29ya3NfaWQgPSB1bmxpc3QobGFwcGx5KHNjaG9sYXJzX3NlbCR3b3JrLCBmdW5jdGlvbihsKSBsJGlkKSksIHdvcmtzX2F1dGhvciA9IHVubGlzdChsYXBwbHkoc2Nob2xhcnNfc2VsJHdvcmssDQogICAgICAgIGZ1bmN0aW9uKGwpIGwkYXV0aG9yKSwgcmVjdXJzaXZlID0gRkFMU0UpLCB3b3Jrc195ZWFyID0gdW5saXN0KGxhcHBseShzY2hvbGFyc19zZWwkd29yaywgZnVuY3Rpb24obCkgbCRwdWJsaWNhdGlvbl95ZWFyKSwNCiAgICAgICAgcmVjdXJzaXZlID0gRkFMU0UpKQ0KDQogICAgZGZfd29ya3MgPC0gZGZfd29ya3NbIWR1cGxpY2F0ZWQoZGZfd29ya3MpLCBdDQoNCiAgICAjIHN0ZXAgNA0KICAgIGlmICh0eXBlID09ICJmaXJzdCIpIHsNCiAgICAgICAgZm9yIChqIGluIDE6bndhdmVzKSB7DQogICAgICAgICAgICBkZl93b3Jrc193IDwtIGRmX3dvcmtzW2RmX3dvcmtzJHdvcmtzX3llYXIgPj0gd2F2ZXNbW2pdXVsxXSAmIGRmX3dvcmtzJHdvcmtzX3llYXIgPD0gd2F2ZXNbW2pdXVsyXSwNCiAgICAgICAgICAgICAgICBdDQogICAgICAgICAgICBmb3IgKGkgaW4gMTpucm93KGRmX3dvcmtzX3cpKSB7DQogICAgICAgICAgICAgICAgZWdvIDwtIGRmX3dvcmtzX3ckd29ya3NfYXV0aG9yW2ldW1sxXV0kYXVfaWRbMV0NCiAgICAgICAgICAgICAgICBhbHRlcnMgPC0gZGZfd29ya3NfdyR3b3Jrc19hdXRob3JbaV1bWzFdXSRhdV9pZFstMV0NCiAgICAgICAgICAgICAgICBpZiAoc3VtKGlkcyAlaW4lIGVnbykgPiAwICYgc3VtKGlkcyAlaW4lIGFsdGVycykgPiAwKSB7DQogICAgICAgICAgICAgICAgICBuZXRzW2osIHdoaWNoKGlkcyAlaW4lIGVnbyksIHdoaWNoKGlkcyAlaW4lIGFsdGVycyldIDwtIDENCiAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICB9DQogICAgICAgIH0NCiAgICB9DQoNCiAgICBpZiAodHlwZSA9PSAibGFzdCIpIHsNCiAgICAgICAgZm9yIChqIGluIDE6bndhdmVzKSB7DQogICAgICAgICAgICBkZl93b3Jrc193IDwtIGRmX3dvcmtzW2RmX3dvcmtzJHdvcmtzX3llYXIgPj0gd2F2ZXNbW2pdXVsxXSAmIGRmX3dvcmtzJHdvcmtzX3llYXIgPD0gd2F2ZXNbW2pdXVsyXSwNCiAgICAgICAgICAgICAgICBdDQogICAgICAgICAgICBmb3IgKGkgaW4gMTpucm93KGRmX3dvcmtzX3cpKSB7DQogICAgICAgICAgICAgICAgZWdvIDwtIHJldihkZl93b3Jrc193JHdvcmtzX2F1dGhvcltpXVtbMV1dJGF1X2lkKVsxXQ0KICAgICAgICAgICAgICAgIGFsdGVycyA8LSByZXYoZGZfd29ya3NfdyR3b3Jrc19hdXRob3JbaV1bWzFdXSRhdV9pZClbLTFdDQogICAgICAgICAgICAgICAgaWYgKHN1bShpZHMgJWluJSBlZ28pID4gMCAmIHN1bShpZHMgJWluJSBhbHRlcnMpID4gMCkgew0KICAgICAgICAgICAgICAgICAgbmV0c1tqLCB3aGljaChpZHMgJWluJSBlZ28pLCB3aGljaChpZHMgJWluJSBhbHRlcnMpXSA8LSAxDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQogICAgfQ0KDQogICAgaWYgKHR5cGUgPT0gImFsbCIpIHsNCiAgICAgICAgZm9yIChqIGluIDE6bndhdmVzKSB7DQogICAgICAgICAgICBkZl93b3Jrc193IDwtIGRmX3dvcmtzW2RmX3dvcmtzJHdvcmtzX3llYXIgPj0gd2F2ZXNbW2pdXVsxXSAmIGRmX3dvcmtzJHdvcmtzX3llYXIgPD0gd2F2ZXNbW2pdXVsyXSwNCiAgICAgICAgICAgICAgICBdDQogICAgICAgICAgICBmb3IgKGkgaW4gMTpucm93KGRmX3dvcmtzX3cpKSB7DQogICAgICAgICAgICAgICAgZWdvcyA8LSBkZl93b3Jrc193JHdvcmtzX2F1dGhvcltpXVtbMV1dJGF1X2lkDQogICAgICAgICAgICAgICAgaWYgKHN1bShpZHMgJWluJSBlZ29zKSA+IDApIHsNCiAgICAgICAgICAgICAgICAgIG5ldHNbaiwgd2hpY2goaWRzICVpbiUgZWdvcyksIHdoaWNoKGlkcyAlaW4lIGVnb3MpXSA8LSAxDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQogICAgfQ0KICAgIG91dHB1dCA8LSBsaXN0KCkNCiAgICBvdXRwdXQkZGF0YSA8LSBzY2hvbGFyc19zZWwNCiAgICBvdXRwdXQkbmV0cyA8LSBuZXRzDQogICAgcmV0dXJuKG91dHB1dCkNCn0NCmBgYA0KDQoNCkV4YW1wbGUgaW4gY2xhc3MgZnJvbSAxMCBPY3RvYmVyDQpTaWVuYSBkZXBlbmRlbnQgdmFyaWFibGUgDQoNCmBgYHtyfQ0KIyBTdGVwIDE6IGxvYWQgZGF0YQ0KbGlicmFyeShSU2llbmEpDQo/c2llbmFEZXBlbmRlbnQgI2xvb2sgZm9yIGV4YW1wbGVzIC0gc2NyaXB0IGZvciBob3cgdG8gcnVuIHN0dWZmIA0KDQoNCiMgdGhlbiBjaGVjayB3YXZlcyBhdmFpbGFibGUNCnM1MDEgI25ldHdvcmsgYXQgdGltZXBvaW50IDENCnM1MDIgI25ldHdvcmsgYXQgdGltZXBvaW50IDINCnM1MDMgI25ldHdvcmsgYXQgdGltZXBvaW50IA0KDQoNCm15bmV0MSA8LSBzaWVuYURlcGVuZGVudChhcnJheShjKHM1MDEsIHM1MDIsIHM1MDMpLCBkaW09Yyg1MCwgNTAsIDMpKSkNCm15YmVoIDwtIHNpZW5hRGVwZW5kZW50KHM1MGEsIHR5cGU9ImJlaGF2aW9yIikNCg0KICMgbG9vayBmb3Igc21va2luZyBhbmQgZHJpbmtpbmcgYmVoYXZpb3JzDQoNCnNtb2tlIDwtIHM1MHMgI3RpbWUgdmFyeWluZyBjb3ZhcmlhdGUuIFRpbWUgY29uc3RhbnQgY292YXIgLSB2YXJDb3Zhcg0Kc21va2UgPC0gdmFyQ292YXIoczUwcykNCg0KbXlkYXRhX2V4YW1wbGUgPC0gc2llbmFEYXRhQ3JlYXRlKG15bmV0MSwgbXliZWgsIHNtb2tlKQ0KDQoNCg0KIyBTdGVwIDI6IGxvb2sgYXQgZGF0YQ0KI3ByaW50IHJlcG9ydCBvbiBkYXRhIHJlcG9ydHMNCg0KcHJpbnQwMVJlcG9ydChteWRhdGFfZXhhbXBsZSkNCg0KDQojIFN0ZXAgMzogYWRkIGVmZmVjdHMgDQpteWVmZl9leGFtcGxlIDwtIGdldEVmZmVjdHMobXlkYXRhX2V4YW1wbGUpDQpteWVmZl9leGFtcGxlDQoNCg0KDQpteWVmZl9leGFtcGxlIDwtIGluY2x1ZGVFZmZlY3RzKG15ZWZmX2V4YW1wbGUsIHVuZXF1YWxYLCBuYW1lPSJteW5ldDEiLCBpbnRlcmFjdGlvbjEgPSAic21va2UiKQ0KbXllZmZfZXhhbXBsZQ0KDQoNCiNtYWtlIGFsZ29yaXRobSB0byB0aGVuIGVzdGltYXRlIGl0DQphbGdvX2V4IDwtIHNpZW5hQWxnb3JpdGhtQ3JlYXRlKHByb2puYW1lID0gInRlc3RfZXgiKQ0KYW5zd2VyX2V4IDwtIHNpZW5hMDcoYWxnb19leCwgZGF0YT1teWRhdGFfZXhhbXBsZSwgZWZmZWN0cz1teWVmZl9leGFtcGxlLCByZXR1cm5EZXBzID0gVFJVRSkNCg0KYW5zd2VyX2V4DQoNCg0KI2RvZXMgaXQgY2hhbmdlIGlmIGRlcGVuZGVudCBYIA0KbXllZmZfZXhhbXBsZSA8LSBpbmNsdWRlRWZmZWN0cyhteWVmZl9leGFtcGxlLCB1bmVxdWFsWCwgbmFtZT0ibXluZXQxIiwgaW50ZXJhY3Rpb24xID0gIm15YmVoIikgI25hbWUgPSBuZXR3b3JrIGRlcGVuZGVudCB2YXJpYWJsZSwgaW50ZXJhY3Rpb24gMSBpcyBjb3ZhcmlhdGUgKHNtb2tpbmcpIC0gaWYgaGF2ZSBtdWx0aXBsZSBuZXRvd3JrcywgdGhlbiBjb3VsZCBoYXZlIHVuZXF1YWxYIHdpdGggcmVzcGVjdCB0byBYLiBXZSByZXBsYWNlZCBzbW9rZSB3aXRoIG15IGJlaGF2aW9yLCBhbmQgcmVydW4gdGhlIHNpZW5hIG1vZGVsLiBUaGlzIGlzIGFuIGFsZ29yaXRobSwgY2FuIGFzayBSU2llbmEgdG8gcmVmZXJlbmNlIHByZXZpb3VzIHJlc3VsdCB3aXRoICdwcmV2YW5zPUFOUycgYWZ0ZXIgcmV0dXJuRGVwdHMgPSBUUlVFDQphbnN3ZXJfZXggPC0gc2llbmEwNyhhbGdvX2V4LCBkYXRhPW15ZGF0YV9leGFtcGxlLCBlZmZlY3RzPW15ZWZmX2V4YW1wbGUsIHJldHVybkRlcHMgPSBUUlVFKQ0KDQphbnN3ZXJfZXgNCiMgbG9va2luZyBhdCByZXN1bHRzLCBteWJlaCA9IGRyaW5raW5nIC0tIGVnbyBsZXNzIGxpa2VseSB0byBzcGVuZCB0aW1lIHdpdGggcGVvcGxlIHdobyBkcmluayBtb3JlIG9yIGxlc3MgdGhhbiB0aGVtLiBlZ28gYWxzbyBsZXNzIGxpa2VseSB0byBzcGVuZCB0aW1lIHdpdGggcGVvcGxlIHdobyBzbW9rZSBtb3JlIG9yIGxlc3MsIHRvIGEgbGVzc2VyIGV4dGVudC4gQ2FuIHVzZSB1bmVxdWFsWCBmb3IgZGVwZW5kZW50IHZhcmlhYmxlcyBhbmQgY292YXJpYXRlcy4ga2V5IGRpZmZlcmVuY2UgaW4gZXN0aW1hdGlvbiBwcm9jZWR1cmU6IA0KIyB3ZSBhcmUgYWxzbyBtb2RlbGluZyBiZWhhdmlvcmFsIHJlc3VsdHMgLSBiZWhhdmlvciBjaGFuZ2luZyBvdmVyIHRpbWUsIHNpbXVsYXRlZCB2aWEgbWluaXN0ZXAgbG9naWMgKG9uZSBzdGVwIHVwIG9yIGRvd24pLiBUaGUgY3J1Y2lhbCBkaWZmZXJlbmNlOiBkdXJpbmcgdGhlIGFsZ29yaXRobSANCiNJZiBjb3VudCBzdGF0aXN0aWMgZm9yIHNtb2tlLCB0aGVuIGJldHdlZW4gdGltZSBwb2ludCAxIGFuZCAyIHdlIHVzZSB2YWx1ZSBmcm9tIHRpbWVwb2ludCAxLiBiZXR3ZWVuIDItMywgdXNlIHRpbWUgcG9pbnQgMi4gQnV0IHdpdGhpbiB0aGUgdmFyaWFibGUsIHRoZSBlZ28gbGV2ZWwgYmVoYXZpb3IgaXMgY2hhbmdpbmcuIGlzIG5vdCB1c2luZyB0aGUgdmFsdWUgYXMgb2JzZXJ2ZWQgYXQgdDEgLSBpdCBpcyB1c2luZyB0aGUgdmFsdWUgYXMgaXMgY3VycmVudGx5IHNpbXVsYXRlZC4gDQoNCg0KDQoNCg0KI2NvdWxkIGV4Y2x1ZGUgdmFyaWFibGUgdG8gdGhlbiBpbmNsdWRlIGFzIGNvdmFyaWF0ZSBlZmZlY3QuIA0KDQpteWJlaCA8LSBzaWVuYURlcGVuZGVudChzNTBhLCB0eXBlPSJiZWhhdmlvciIpICNkZWZpbmVkIGFzIGRlcGVuZGVudCB2YXJpYWJsZSANCmRyaW5raW5nIDwtIHZhckNvdmFyKHM1MGEpICNkZWZpbmVkIGFzIGNvdmFyaWF0ZSB2YXJpYWJsZSANCg0KI3VwZGF0ZSBkYXRhIG9iamVjdDogDQpteWRhdGFfZXhhbXBsZSA8LSBzaWVuYURhdGFDcmVhdGUobXluZXQxLCBteWJlaCwgZHJpbmtpbmcsIHNtb2tlKQ0KDQoNCiNhbmQgZWZmZWN0cyBvYmplY3Q6IA0KbXllZmZfZXhhbXBsZSA8LSBpbmNsdWRlRWZmZWN0cyhteWVmZl9leGFtcGxlLCB1bmVxdWFsWCwgbmFtZT0ibXluZXQxIiwgaW50ZXJhY3Rpb24xID0gInNtb2tlIikNCg0KbXllZmZfZXhhbXBsZSA8LSBpbmNsdWRlRWZmZWN0cyhteWVmZl9leGFtcGxlLCB1bmVxdWFsWCwgbmFtZT0ibXluZXQxIiwgaW50ZXJhY3Rpb24xID0gImRyaW5raW5nIikNCg0KYWxnb19leDIgPC0gc2llbmFBbGdvcml0aG1DcmVhdGUocHJvam5hbWUgPSAidGVzdF9leCIpDQoNCmFuc3dlcl9leCA8LSBzaWVuYTA3KGFsZ29fZXgyLCBkYXRhPW15ZGF0YV9leGFtcGxlLCBlZmZlY3RzPW15ZWZmX2V4YW1wbGUsIHJldHVybkRlcHMgPSBUUlVFKQ0KYW5zd2VyX2V4DQoNCiN0aGVuIHRoZSBuZXR3b3JrIGR5bmFtaWNzIGNoYW5nZSANCiMgaW50ZXJwcmV0YXRpb24gb2YgdGhlIHJhdGUgY29uc3RhbnQgLSB0aGUgYXZlcmFnZSBhbW91bnQgb2YgbWluaXN0ZXBzIGVhY2ggZWdvIGlzIG1ha2luZyBiZXR3ZWVuIHRoZSB0d28gb2JzZXJ2YXRpb25zDQoNCiNiZWhhdmlvcmFsIGR5bmFtaWNzOiANCiMgdGhlIHJhdGUgY29uc3RhbnQ6IHRoZSBudW1iZXIgb2Ygc3RlcHMgaW4gdGhlIGJlaGF2aW9yYWwgYXNwZWN0IA0KDQojc3RhdGlzdGljIGZvciBsaW5lYXIgc2hhcGUgLSBsaW5lYXIgc2hhcGUgZWZmZWN0IC0gdGhlIHZhbHVlIG9mIHRoZSAqY2VudGVyZWQqIGJlaGF2aW9yYWwgdmFyaWFibGUgKGF2ZXJhZ2UgaW4gdGhlIHRvdGFsIHNhbXBsZSkuIA0KIyBpZiBwb3NpdGl2ZSwgdHJ5IHRvIGluY3JlYXNlIGJlaGF2aW9yLiBlZmZlY3QgaXMgejEgKHplZCBzY29yZSksIHdpdGggdGhlIG9wdGlvbnMgb2YgMSwgMCwgb3IgLTEuIGJlaGF2aW9yIGluY3JlYXNlcyBiZWNhdXNlIHBvc2l0aXZlbHkgZXZhbHVhdGVzIDEgbW9yZSB0aGFuIDAsIG1vcmUgdGhhbiAtMS4gQXQgc29tZSBwb2ludCwgdGhvdWdoLCBiZWhhdmlvciB3aWxsIHN0b3AgaW5jcmVhc2luZyAtIHRoYXQgaXMgejIgKHNxdWFyZWQhKS4gc28sIHBhcmFtZXRlciBtb2RlcmF0ZXMgaXRzZWxmIHdpdGggdGltZT8/IA0KDQojIHRoZXNlIGFyZSB0aGUgbWluaW11bSBlZmZlY3RzIHRvIGluY2x1ZGUsIGJlY2F1c2UgaXQgcHJlZGljdHMgbWVhbiB2YWx1ZSBvYnNlcnZlIGluIGRhdGFzZXQuIDIgcGFyYW1ldGVycyAtIGVzdGltYXRlIG1lYW4gYmVoYXZpb3IuIGJhc2VkIG9uIG1vZGVsIHJlc3VsdHMsIHdoYXQgaXMgdGhlIG1lYW4gdmFsdWUuIA0KDQojIGJlaGF2aW9yYWwgdmFyaWFibGVzIGluIGRhdGFzZXQgLSBldmVyeXRoaW5nIG9ic2VydmVkIHRoYXQgY2hhbmdlcy4gZXguLCBwb3NpdGlvbiAoZnVuY3RpZSksIGNpdGF0aW9ucywgaW50ZXJkaXNjaXBsaW5hcml0eSBzY29yZS4gUHJvYmxlbTogaXMgdGltZSB3aW5kb3cgbGFyZ2UgZW5vdWdodCB0byBzZWUgY2hhbmdlPyBhbmQgb3ZlciB0aW1lLCBiZWhhdmlvcmFsIHZhcmlhYmxlIGlzIG9ubHkgY2hhbmdpbmcgLSB3aGljaCB0aGVuIG11c3QgYmUgY2FsY3VsYXRlZCBhcyBjb250aW51b3VzIGRlcGVuZGVkIHZhcmlhYmxlLiANCg0KDQpgYGANCg0KDQo=